<?php
/*=============================================================================
#     FileName: MTCloud.class.php
#         Desc: 欢拓语音视频服务接口SDK
#   LastChange: 2014-03-19 10:54:27
#      History:
=============================================================================*/

/**
 *   提供欢拓语音视频服务开放接口
 */
class MTCloud {

    //注意：$openID 以及 $openToken 需要从欢拓官方获取，并填到参数赋值中。

    /*
    *  合作方ID：欢拓平台的唯一ID
    */
    private $openID = '11221';

    /*
    *  合作方秘钥：欢拓平台唯一ID对应的加密秘钥
    */
    private $openToken = '1e1cde08ab6f24c1bf41ce48a283c529';

    /*
    *   欢拓API接口地址
    */
    private $restUrl = 'http://open.talk-fun.com/portal.php';

    /*
    *   接口访问curl超时时间
    */
    private $timeout = 10;

    /**
     *   返回的数据格式
     */
    private $format = 'json';               //  json OR xml

    /**
     *   SDK版本号(请勿修改)
     */
    private $version = 'php.1.3';

    /**
     *   回调handler
     */
    private $callbackHandler = null;


    /**
     *   状态码
     */
    const CODE_FAIL = -1;           //失败
    const CODE_SUCCESS = 0;         //成功的状态码,返回其它code均为失败
    const CODE_PARAM_ERROR = 10;    //参数错误
    const CODE_SIGN_EXPIRE = 10002; //签名过期
    const CODE_SIGN_ERROR = 10003;  //签名验证错误


    /**
     *   用户支持的角色
     */
    const ROLE_USER = 'user';           //普通用户
    const ROLE_ADMIN = 'admin';         //管理员
    const ROLE_SPADMIN = 'spadmin';     //超级管理员
    const ROLE_GUEST = 'guest';         //游客

    /**
     *   用户定义
     */
    const USER_GENDER_UNKNOW = 0;       //未知生物
    const USER_GENDER_MALE = 1;         //男性
    const USER_GENDER_FEMALE = 2;       //女性

    /**
     *   主播账户类型
     */
    const ACCOUNT_TYPE_MT = 1;       //欢拓账号类型
    const ACCOUNT_TYPE_THIRD = 2;       //合作方账号类型

    /**
     *   直播记录常量
     */
    const LIVE_NO_PLAYBACK = 0;         //没有直播回放的记录
    const LIVE_HAS_PLAYBACK = 1;        //有直播回放的记录


    /**
     *   语音常量
     */
    const VOICE_FLOW_CLOUD = 1;         //语音云模式
    const VOICE_FLOW_LISTEN_ONLY = 2;   //只听模式


    public function __construct($openID = '', $openToken = '') {
        if ($openID) {
            $this->openID = $openID;
        }

        if ($openToken) {
            $this->openToken = $openToken;
        }
    }

    /**
     * 设置欢拓数据响应的格式
     * @param  string $format
     */
    public function setFormat($format) {
        $this->format = $format;
    }


    /**
     * 获取用户access_token,access_key,及房间地址(替代roomGetUrl 方法)
     * @param string $uid 合作方的用户ID
     * @param string $nickname 合作方用户的名称
     * @param string $role 用户角色
     * @param string $roomid 进入的房间ID
     * @param int $expire 有效期
     * @param array $options 可选项，包括： gender:用户性别 , avatar:用户头像
     * @return array
     */
    public function userAccess($uid, $nickname, $role, $roomid, $expire = 3600, $options = array()) {
        $params = array(
            'uid' => $uid,
            'nickname' => $nickname,
            'role' => $role,
            'roomid' => $roomid,
            'expire' => $expire,
            'options' => $options
        );
        return $this->call('user.access', $params);
    }

    public function userAccessPlayback($uid, $nickname, $role, $liveid, $expire, $options = array()) {
        $params = array(
            'uid' => $uid,
            'nickname' => $nickname,
            'role' => $role,
            'liveid' => $liveid,
            'expire' => $expire,
            'options' => $options
        );
        return $this->call('user.access.playback', $params);
    }

    public function userAccessPlaybackAlbum($uid, $nickname, $role, $album_id, $expire, $options = array()) {
        $params = array(
            'uid' => $uid,
            'nickname' => $nickname,
            'role' => $role,
            'album_id' => $album_id,
            'expire' => $expire,
            'options' => $options
        );
        return $this->call('user.access.playbackAlbum', $params);
    }

    /**
     * 获取在线用户列表 (时间区间间隔不大于7天)
     * @param  string $roomid 房间ID
     * @param  string $start_time 查询起始时间,格式:2015-01-01 12:00:00
     * @param  string $end_time 查询结束时间,格式:2015-01-01 13:00:00
     * @return array
     */
    public function userOnlineList($roomid, $start_time, $end_time) {
        $params = array(
            'roomid' => $roomid,
            'start_time' => $start_time,
            'end_time' => $end_time
        );
        return $this->call('user.online.list', $params);
    }


    /**
     * 查询某个房间的状态信息
     * @param int $roomid 房间id
     * @return array               房间信息
     */
    public function roomGetInfo($roomid) {
        $params['roomid'] = $roomid;
        return $this->call('room.getInfo', $params);
    }


    /**
     * 创建一个房间
     * @param      string $roomName 房间名称
     * @return array
     */
    public function roomCreate($roomName, $voiceFlow = self::VOICE_FLOW_CLOUD, $authKey) {
        $params['roomName'] = $roomName;
        $params['voiceFlow'] = $voiceFlow;
        $params['authKey'] = $authKey;
        return $this->call('room.create', $params);
    }


    /**
     * 更新房间信息
     * @param  string $roomid 房间ID
     * @param  array $params 房间信息,包括： roomName:房间名称,authKey:管理员密码
     * @return array
     */
    public function roomUpdate($roomid, $params = array()) {
        $params['roomid'] = $roomid;
        return $this->call('room.update', $params);
    }


    /**
     * 删除一个房间
     * @return array
     */
    public function roomDrop($roomid) {
        $params['roomid'] = $roomid;
        return $this->call('room.drop', $params);
    }


    /**
     * 获取房间列表
     * @param int $page 页码
     * @param int $size 获取房间数量
     * @return array
     */
    public function roomList($page = 1, $size = 10) {
        $params = array(
            'page' => $page,
            'size' => $size
        );
        return $this->call('room.list', $params);
    }


    /**
     * 房间绑定主播账号
     * @param int $roomid 房间ID
     * @param string $account 欢拓主播ID或合作方账号ID
     * @retrun array
     * @return array
     */
    public function roomBindAccount($roomid, $account, $accountType = self::ACCOUNT_TYPE_MT) {
        $params['roomid'] = $roomid;
        $params['account'] = $account;
        $params['accountType'] = $accountType;
        return $this->call('room.live.bindAccount', $params);
    }


    /**
     * 取消房间绑定
     * @param int $roomid 房间ID
     * @param string $account 欢拓主播ID或合作方账号ID
     * @return array
     */
    public function roomUnbindAccount($roomid, $account, $accountType = self::ACCOUNT_TYPE_MT) {
        $params['roomid'] = $roomid;
        $params['account'] = $account;
        $params['accountType'] = $accountType;
        return $this->call('room.live.unbindAccount', $params);
    }


    /**
     * 主播获取登录页面
     * @param string $account 主播账号
     * @return array
     */
    public function zhuboLogin($account) {
        $params['account'] = $account;
        return $this->call('zhubo.login', $params);
    }


    /**
     * 查询主播信息
     * @param string $account 主播账号
     * @param int $accountType 主播账号类型
     * @return array
     */
    public function zhuboGet($account, $accountType = self::ACCOUNT_TYPE_MT) {
        $params['account'] = $account;
        $params['accountType'] = $accountType;
        return $this->call('zhubo.get', $params);
    }


    /**
     * 创建一个主播
     * @param  string $nickname 主播昵称
     * @param  int $accountType 账户类型
     * @param  string $account 合作方主播账户(可选)  当账户类型为合作方账户，填写此项
     * @param  string $password 密码    (可选)  如果账户类型为欢拓账户，填写此项
     * @param  string $intro 简介
     * @return array
     */
    public function zhuboCreate($account, $nickname, $accountType, $password = '', $intro = '') {
        $params['nickname'] = $nickname;
        $params['accountType'] = $accountType;
        $params['account'] = $account;
        $params['password'] = $password;
        $params['intro'] = $intro;
        return $this->call('zhubo.create', $params);
    }


    /**
     *   更新主播信息
     * @param  string $account 主播账号
     * @param  int $accountType 账户类型
     * @param  string $nickname 昵称
     * @param  string $intro 简介
     * @return array
     */
    public function zhuboUpdateInfo($account, $accountType, $nickname, $intro = '') {
        $params['account'] = $account;
        $params['accountType'] = $accountType;
        $params['nickname'] = $nickname;
        $params['intro'] = $intro;
        return $this->call('zhubo.update.info', $params);
    }


    /**
     *   更新主播密码
     * @param  string $account 主播账号
     * @param  int $accountType 账号类型
     * @param  string $password 密码
     * @return  array
     *
     */
    public function zhuboUpdatePassword($account, $accountType, $password) {
        $params['account'] = $account;
        $params['accountType'] = $accountType;
        $params['password'] = $password;
        return $this->call('zhubo.update.password', $params);
    }

    /**
     *   删除一个主播
     * @param  string $account 主播账户
     * @param  int $accountType 账户类型
     * @return array
     */
    public function zhuboDel($account, $accountType) {
        $params['account'] = $account;
        $params['accountType'] = $accountType;
        return $this->call('zhubo.del', $params);
    }


    /**
     *   获取主播列表
     * @param  int $page 页码
     * @param  int $size 每页个数
     * @return array
     */
    public function zhuboList($page = 1, $size = 10) {
        $params = array(
            'page' => $page,
            'size' => $size
        );

        return $this->call('zhubo.list', $params);
    }


    /**
     * 获取某场直播的记录信息及回放地址
     * @param int $liveid 直播记录ID
     * @param int $expire 回放地址有效时间
     * @return array
     */
    public function liveGet($liveid, $expire = 3600) {
        $params = array(
            'liveid' => $liveid,
            'expire' => $expire
        );
        return $this->call('live.get', $params);
    }

    /**
     * 批量获取直播记录及回放地址
     * @param array $liveids
     * @return array
     */
    public function liveGetBatch($liveids, $expire = 3600) {
        $params = array(
            'liveids' => $liveids,
            'expire' => $expire
        );
        return $this->call('live.getBatch', $params);
    }


    /**
     * 获取直播记录列表
     * @param string $startDate 起始日期，格式为:yyyy-mm-dd
     * @param string $endDate 结束日期，格式为:yyyy-mm-dd
     * @param int $page 页码
     * @param int $size 每页条数
     * @return array
     */
    public function liveList($startDate, $endDate, $page = 1, $size = 10, $playback = '') {
        $params = array(
            'startDate' => $startDate,
            'endDate' => $endDate,
            'page' => $page,
            'size' => $size,
            'playback' => $playback
        );
        return $this->call('live.list', $params);
    }

    /**
     * 创建一个专辑
     * @param string $album_name 专辑名称
     * @return array
     */
    public function liveAlbumCreate($album_name, $liveids = array()) {
        $params = array(
            'album_name' => $album_name,
            'liveids' => $liveids
        );
        return $this->call('live.album.create', $params);
    }

    /**
     * 获取一个直播专辑
     * @param string $album_id 专辑ID
     * @param int $expire 地址有效时间
     * @return array
     */
    public function liveAlbumGet($album_id, $expire = 3600) {
        $params = array(
            'album_id' => $album_id,
            'expire' => $expire
        );
        return $this->call('live.album.get', $params);
    }

    /**
     * 删除一个专辑
     * @param string $album_id 专辑ID
     * @return array
     */
    public function liveAlbumDelete($album_id) {
        $params = array(
            'album_id' => $album_id
        );
        return $this->call('live.album.delete', $params);
    }

    /**
     * 往专辑增加一个回放记录
     * @param string $album_id 专辑ID
     * @param array $liveids 回放记录ID列表
     * @return array
     */
    public function liveAlbumAdd($album_id, $liveids = array()) {
        $params = array(
            'album_id' => $album_id,
            'liveids' => $liveids
        );
        return $this->call('live.album.add', $params);
    }

    /**
     * 从专辑里面清除某个回放
     * @param int $album_id 专辑ID
     * @param array $liveids 回放记录ID列表
     * @return array
     */
    public function liveAlbumRemove($album_id, $liveids = array()) {
        $params = array(
            'album_id' => $album_id,
            'liveids' => $liveids
        );
        return $this->call('live.album.remove', $params);
    }

    /**
     * 根据房间及时间获取回放记录
     * @param String $roomid 房间ID
     * @param String $start_time 开始时间 格式:2014-12-26 12:00:00
     * @param int $expire 地址有效期
     * @return array
     */
    public function liveRoomGet($roomid, $start_time, $expire = 3600) {
        $params = array(
            'roomid' => $roomid,
            'start_time' => $start_time,
            'expire' => $expire
        );
        return $this->call("live.room.get", $params);
    }

    /**
     * 根据房间及时间区间获取回放记录
     * @param String $roomid 房间ID
     * @param String $start_time 起始区间时间  格式：2014-12-26 00:00:00
     * @param String $end_time 结束区间时间  格式: 2014-12-26 12:00:00
     * @param int $expire 有效期
     * @return array
     */
    public function liveRoomList($roomid, $start_time, $end_time, $expire = 3600) {
        $params = array(
            'roomid' => $roomid,
            'start_time' => $start_time,
            'end_time' => $end_time,
            'expire' => $expire
        );
        return $this->call("live.room.list", $params);
    }

    /**
     * 增加一个直播课程
     * @param String $course_name 课程名称
     * @param String $account 发起直播课程的主播账号
     * @param String $start_time 课程开始时间,格式: 2015-01-10 12:00:00
     * @param String $end_time 课程结束时间,格式: 2015-01-10 13:00:00
     * @return array
     */
    public function liveCourseAdd($course_name, $account, $start_time, $end_time) {
        $params = array(
            'course_name' => $course_name,
            'account' => $account,
            'start_time' => $start_time,
            'end_time' => $end_time
        );
        return $this->call('live.course.add', $params);
    }

    /**
     * 查询课程信息
     * @param string $course_id 课程ID
     * @return array
     */
    public function liveCourseGet($course_id) {
        $params = array('course_id' => $course_id);
        return $this->call('live.course.get', $params);
    }

    /**
     * 删除课程
     * @param String $course_id 课程ID
     * @return array
     */
    public function liveCourseDelete($course_id) {
        $params = array('course_id' => $course_id);
        return $this->call('live.course.delete', $params);
    }

    /**
     * 课程列表(将返回开始时间在区间内的课程)
     * @param String $start_time 开始时间区间,格式: 2015-01-01 12:00:00
     * @param String $end_time 结束时间区间,格式: 2015-01-02 12:00:00
     * @return array
     */
    public function liveCourseList($start_time, $end_time) {
        $params = array('start_time' => $start_time, 'end_time' => $end_time);
        return $this->call('live.course.list', $params);
    }

    /**
     * 更新课程信息
     * @param String $course_id 课程ID
     * @param String $account 发起直播课程的主播账号
     * @param String $course_name 课程名称
     * @param String $start_time 课程开始时间,格式:2015-01-01 12:00:00
     * @param String $end_time 课程结束时间,格式:2015-01-01 13:00:00
     * @return array
     */
    public function liveCourseUpdate($course_id, $account, $course_name, $start_time, $end_time) {
        $params = array(
            'course_id' => $course_id,
            'course_name' => $course_name,
            'account' => $account,
            'start_time' => $start_time,
            'end_time' => $end_time
        );
        return $this->call('live.course.update', $params);
    }


    //==================================================
    //              回调逻辑
    //==================================================
    /**
     *   注册回调函数
     *   示例：  http://www.example.com/callback.php
     *   class ExampleHandler {
     *        public function handler($cmd,$params){
     *            if($cmd === 'user.login'){
     *                //do something...
     *                $response = array('code'=>MTCloud::CODE_SUCCESS,'data'=>array('uid'=>'abcde@qq.com','nickname'=>'昵称','role'=>MTCloud::ROLE_ADMIN));
     *            }
     *            return $response;
     *        }
     *   }
     *
     *   $MTCloud = new MTCloud();
     *   $MTCloud->registerCallbackHandler(array(new ExampleHandler,'handler'));
     *   $MTCloud->callbackService();
     * @param array $callbackHandler
     */
    public function registerCallbackHandler($callbackHandler = array()) {
        $this->callbackHandler = $callbackHandler;
    }

    /**
     *   回调参数验证、处理，及响应
     */
    public function callbackService() {
        if (!$this->callbackHandler) {
            throw new MTCloudException('回调 handler 未设置!');
        }

        $sysParams = $_POST;

        if (!isset($sysParams['sign']) || $this->generateSign($sysParams) !== $sysParams['sign']) {
            self::response(array('code' => self::CODE_SIGN_ERROR));
        }

        if ($_SERVER['REQUEST_TIME'] - $sysParams['timestamp'] > 7200) {
            self::response();
        }

        $retval = call_user_func_array($this->callbackHandler, array($sysParams['cmd'], json_decode($sysParams['params'], true)));

        self::response($retval);
    }

    public function response($retval) {
        exit(json_encode($retval));
    }


    //==================================================
    //              以下为系统逻辑
    //==================================================

    /**
     * 构造欢拓云sign
     * @param array $params 业务参数
     * @param string $salt 加密salt
     * @return string      生成的秘钥
     */
    public function generateSign($params, $salt = '') {
        unset($params['sign']);
        ksort($params);
        $secret_key = $salt ? md5(substr($this->openToken, 6, 16) . $salt) : $this->openToken;
        $keyStr = "";
        foreach ($params as $key => $value) {
            $keyStr .= $key . $value;
        }
        $keyStr .= $secret_key;
        $sign = md5($keyStr);
        return $sign;
    }


    /**
     * 调用欢拓API
     * @param  string $cmd 调用的API名称
     * @param  array $params API参数
     * @return array
     */
    public function call($cmd, $params = array()) {
        $sysParams = array();
        $sysParams['openID'] = $this->openID;
        $sysParams['timestamp'] = $_SERVER['REQUEST_TIME'];
        $sysParams['cmd'] = $cmd;
        $sysParams['params'] = urlencode(json_encode($params));
        $sysParams['ver'] = $this->version;
        $sysParams['format'] = $this->format;
        $sysParams['sign'] = $this->generateSign($sysParams);

        return $this->_request($this->restUrl . '?' . http_build_query($sysParams), 'GET');
    }

    private function _request($url, $method = 'POST', $data = array()) {
        $options = array(
            CURLOPT_HTTPHEADER => true,
            CURLOPT_TIMEOUT => $this->timeout,
            CURLOPT_RETURNTRANSFER => 1,
            CURLOPT_HTTPHEADER => array(
                'Expect:'
            ),
            CURLOPT_USERAGENT => 'MT-PHP-SDK',
        );

        if ($method == 'POST') {
            $options[CURLOPT_POST] = 1;
            $options[CURLOPT_POSTFIELDS] = is_array($data) ? http_build_query($data) : $data;
        }

        $curl = curl_init($url);
        curl_setopt_array($curl, $options);

        $page = curl_exec($curl);

        $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);

        if ($statusCode === 200) {

            if ($this->format === 'xml') {
                $retval = $page;
            } else {
                $retval = json_decode($page, true);
                if (!is_array($retval)) {
                    throw new MTCloudException('返回的数据错误！' . $page);
                }
            }

            return $retval;
        } else {
            return array('code' => -100, 'msg' => 'CURL ERROR: no:' . curl_errno($curl) . ',msg:' . curl_error($curl), 'statusCode' => $statusCode);
        }
    }


    /**
     * 生成一个游客ID
     * @return string
     */
    public function generateGuestId() {
        if (function_exists('com_create_guid')) {
            return com_create_guid();
        } else {
            mt_srand((double)microtime() * 10000);//optional for php 4.2.0 and up.
            $charid = strtoupper(md5(uniqid(rand(), true)));
            $hyphen = chr(45);// "-"
            $uuid = substr($charid, 0, 8) . $hyphen
                . substr($charid, 8, 4) . $hyphen
                . substr($charid, 12, 4) . $hyphen
                . substr($charid, 16, 4) . $hyphen
                . substr($charid, 20, 12);
            return $uuid;
        }
    }
}

class MTCloudException extends Exception {
}
